package com.ulook.lookplanet.service;

import com.ulook.lookplanet.bean.TPlanet;
import com.ulook.lookplanet.bean.VMatchingCard;
import com.ulook.lookplanet.mapper.MatchingMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 描述：
 *
 * @author L1998
 * @date 2021/5/11
 */
@Service
public class MatchingService {

    @Autowired
    private MatchingMapper mapper;

    /**
     * 获取推荐列表
     */
    public List<VMatchingCard> getMatchingList(int userId){
        List<VMatchingCard> cards = new ArrayList<>();
        HashMap<Integer, Double> res = recommendUser(userId);
        if(res.size() <= 5){
            for(Integer key : res.keySet()){
                VMatchingCard card = mapper.getMatchingCard(key);
                card.setHpd((int)(res.get(key).doubleValue()));
                cards.add(card);
            }
        }else {
            int i = 0;
            for(Integer key : res.keySet()){
                if(i == 5){
                    break;
                }
                VMatchingCard card = mapper.getMatchingCard(key);
                card.setHpd((int)(res.get(key).doubleValue()));
                cards.add(card);
                i++;
            }
        }
        return cards;
    }

    /**
     * 设置所属行星
     */
    @Transactional
    public TPlanet updatePlanet(int userId, String planetId){
        mapper.updatePlanet(userId, planetId);
        return mapper.getPlanetInfo(planetId);
    }

    /**
     * 推荐算法
     */
    private HashMap<Integer, Double> recommendUser(int uid){
        List<Integer> userList;
        userList = mapper.getAllUserIdList();
        int N = userList.size();
//        System.out.println("用户数量："+N);
        int[][] sparseMatrix=new int[N][N]; //建立用户稀疏矩阵，用于用户相似度计算【相似度矩阵】
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++)
                sparseMatrix[i][j] = 0;
        }
        Map<Integer, Integer> userItemLength = new HashMap<>();//存储每一个用户对应的不同物品总数  eg: A 3
        Map<String, Set<Integer>> itemUserCollection = new HashMap<>();//建立物品到用户的倒排表 eg: a A B
        Set<String> items = new HashSet<>();//辅助存储物品集合
        Map<Integer, Integer> userID = new HashMap<>();//辅助存储每一个用户的用户ID映射:user->id
        Map<Integer, Integer> idUser = new HashMap<>();//辅助存储每一个ID对应的用户映射:id->user

        for(int i=0; i<N; i++){ //依次处理N个用户
            int user = userList.get(i);
            List<String> itemList = mapper.getLikeArticleByUserId(user);
            itemList.addAll(mapper.getCollectArticleByUserId(user));
//            System.out.println("UserID:"+user+" 点赞收藏："+itemlist);
            userItemLength.put(user,itemList.size());
            //用户ID与稀疏矩阵建立对应关系
            userID.put(user,i);
            idUser.put(i,user);

            //1建立物品--用户倒排表
            for(int j=0; j < itemList.size(); j++){
                String topic = itemList.get(j);
                if(items.contains(topic)){ //如果已经包含对应的物品--用户映射，直接添加对应的用户
                    itemUserCollection.get(topic).add(user);
                }else{//否则创建对应物品--用户集合映射
                    items.add(topic);
                    //创建物品--用户倒排关系
                    itemUserCollection.put(topic, new HashSet<Integer>());
                    itemUserCollection.get(topic).add(user);
                }
            }
        }
        //输出倒排关系表
        System.out.println("输出倒排关系表：\n"+itemUserCollection.toString());

        //2计算相似度矩阵【稀疏】
        Set<Map.Entry<String, Set<Integer>>> entrySet = itemUserCollection.entrySet();
        Iterator<Map.Entry<String, Set<Integer>>> iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Set<Integer> commonUsers=iterator.next().getValue();
            for(int user_u : commonUsers){
                for(int user_v : commonUsers){
                    if(user_u == user_v){
                        continue;
                    }
                    //计算用户u与用户v都有正反馈的物品总数
                    sparseMatrix[userID.get(user_u)][userID.get(user_v)]+=1;
                }
            }
        }
        //计算用户之间的相似度【余弦相似性】
        Integer recommendUserId = userID.get(uid);
        HashMap<Integer, Double> res = new HashMap<>();
        for(int j=0; j<sparseMatrix.length; j++){
            if(j != recommendUserId){
                System.out.println(idUser.get(recommendUserId)+"--"+idUser.get(j)+"相似度:"
                        + sparseMatrix[recommendUserId][j]/Math.sqrt(userItemLength.get(idUser.get(recommendUserId))*userItemLength.get(idUser.get(j))));

                double cos = sparseMatrix[recommendUserId][j] / Math.sqrt(userItemLength.get(idUser.get(recommendUserId)) * userItemLength.get(idUser.get(j)));
                System.out.println("cos: "+cos);
                if (Double.isNaN(cos) || cos == 0){
                    cos = 0.1;
                }
                res.put(idUser.get(j), (cos*12)+80);
            }
        }
        return res;

    }

}
